<template>
  <view class="common-waterfall-flow">
    <view class="load-list">
      <view v-for="item in loadData" :key="item.id" class="item">
        <!-- 图片类型 -->
        <image v-if="item.type === 'image'" :src="item.imageSrc" mode="widthFix" @load="handleLoad($event, item)" />

        <!-- 视频类型 -->
        <CommonVideo v-if="item.type === 'video'" :id="item.id.toString()" :src="item.videoSrc" @load="handleLoad($event, item)" />
      </view>
    </view>

    <view v-for="(column, index) in columnData" :key="index" class="waterfall-flow-column" :style="{ width: columnWidth + 'px' }">
      <view v-for="item in column.filter(item => !!item)" :key="item.id" class="waterfall-flow-item" :style="{ marginBottom: gap + 'px' }">
        <!-- 图片类型 -->
        <image v-if="item.type === 'image'" :src="item.imageSrc" mode="widthFix" />

        <!-- 视频类型 -->
        <view class="video-box" @click="handlePlay(`video-${item.id}`)">
          <video v-if="item.type === 'video'" :id="`video-${item.id}`" class="video" :style="{ height: item._height + 'px' }" :src="item.videoSrc" :muted="true" :controls="false" :show-center-play-btn="false" />
          <text v-if="item.type === 'video'" class="iconfont icon-play" />
        </view>

        <!-- 其他内容 -->
        <view class="item-content">
          <view class="title">{{ item.title }}</view>
          <view class="game">{{ item.game }}</view>
          <view class="more">
            <view class="user">
              <image :src="item.user.avatar" mode="widthFix" />
              <text>{{ item.user.name }}</text>
            </view>
            <view :class="['like', { on: item.isLike }]">
              <text class="iconfont icon-like" />
              <text>{{ item.like }}</text>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import CommonVideo from "@/components/Video.vue"
import { isWeixin } from "@/utils"
import { onMounted, onUnmounted, ref, toRaw, watch } from "vue"

interface ItemData {
  id: string | number
  type: "image" | "video"
  imageSrc: string
  videoSrc: string
  title: string
  game: string
  user: {
    name: string
    avatar: string
  }
  like: number
  isLike: boolean
  // 计算后的高度（用于瀑布流布局）
  _height?: number
}

/** props */
const props = withDefaults(defineProps<{
  // 数据列表
  list: ItemData[]
  // 列数
  columnCount?: number
  // 列间距
  gap?: number
}>(), {
  columnCount: 2,
  gap: uni.upx2px(10)
})

/** data */
const columnWidth = ref(0)
const columnData = ref<ItemData[][]>([])
const loadData = ref<ItemData[]>([])
const currentPlay = ref<string>("")

// 初始化列
const initColumns = () => {
  columnData.value = Array.from({ length: props.columnCount }, () => [])
}

// 计算列宽度
const calculateColumnWidth = () => {
  return new Promise<void>((resolve) => {
    const query = uni.createSelectorQuery()
    query.select(".common-waterfall-flow").boundingClientRect((data: any) => {
      columnWidth.value = (data.width - (props.columnCount - 1) * props.gap) / props.columnCount
      resolve()
    }).exec()
  })

}

// 分配元素到最短的列
const distributeItems = () => {
  if (loadData.value.length === 0) return

  // 如果列未初始化，先初始化
  if (columnData.value.length !== props.columnCount) {
    initColumns()
  }

  // 清空现有列（保留已计算的高度）
  const columnHeights = columnData.value.map(column =>
    column.reduce((sum, item) => sum + (item._height || 0) + props.gap, 0)
  )

  // 分配新项目
  for (const index in loadData.value) {
    const item = loadData.value[index]

    // 如果未读取高度，跳过
    if (item._height === undefined) continue

    // 如果已经分配过，跳过
    if (columnData.value.some(column => column.includes(item))) continue

    // 找到最短的列
    let shortestColumnIndex = 0
    let minHeight = columnHeights[0]

    for (let i = 1; i < columnHeights.length; i++) {
      if (columnHeights[i] < minHeight) {
        minHeight = columnHeights[i]
        shortestColumnIndex = i
      }
    }

    // 添加到最短列
    columnData.value[shortestColumnIndex][index] = item
    // 更新列高度（如果已经有计算高度）
    if (item._height) {
      columnHeights[shortestColumnIndex] += item._height + props.gap
    }
  }
}

// 图片或视频加载完成后的回调
const handleLoad = (event: any, item: ItemData) => {
  if (!item._height && columnWidth.value) {
    // 根据原始宽高比计算实际显示高度
    item._height = Math.ceil(columnWidth.value / event.detail.width * event.detail.height)

    // 重新分配项目
    distributeItems()
  }
}

// 播放视频
const handlePlay = (id: string) => {
  if (isWeixin) {
    WeixinJSBridge.invoke("getNetworkType", {}, () => {
      if (currentPlay.value === "" || currentPlay.value !== id) {
        uni.createVideoContext(currentPlay.value).pause()
        uni.createVideoContext(id).play()
        currentPlay.value = id
      } else {
        currentPlay.value = ""
        uni.createVideoContext(id).pause()
      }
    })
    return
  }

  if (currentPlay.value === "" || currentPlay.value !== id) {
    uni.createVideoContext(currentPlay.value).pause()
    uni.createVideoContext(id).play()
    currentPlay.value = id
  } else {
    currentPlay.value = ""
    uni.createVideoContext(id).pause()
  }
}

// 暂停视频
const handlePause = () => {
  if (currentPlay.value) {
    uni.createVideoContext(currentPlay.value).pause()
    currentPlay.value = ""
  }
}


// 窗口大小改变时重新计算
const handleResize = () => {
  calculateColumnWidth().then(() => {
    distributeItems()
  })
}

// 初始化
onMounted(() => {
  calculateColumnWidth().then(() => {
    initColumns()
    distributeItems()
    window.addEventListener("resize", handleResize)
  })
})

onUnmounted(() => {
  window.removeEventListener("resize", handleResize)
})

// 监听列表变化
watch(() => props.list, () => {
  loadData.value = JSON.parse(JSON.stringify(toRaw(props.list)))

  if (props.list.length === 0) {
    initColumns()
  }

  distributeItems()
}, { deep: true })

// 监听列数变化
watch(() => props.columnCount, () => {
  initColumns()
  distributeItems()
})

// 暴露组件方法
defineExpose({
  pause: handlePause,
  play: handlePlay
})

// // 懒加载指令
// const vLazyLoad = {
//   mounted(el: HTMLElement) {
//     const observer = new IntersectionObserver((entries) => {
//       for (const entry of entries) {
//         if (entry.isIntersecting) {
//           const lazyElement = entry.target as HTMLImageElement | HTMLVideoElement

//           if (lazyElement.tagName === "UNI-IMAGE") {
//             const img = lazyElement as HTMLImageElement
//             if (img.dataset.src) {
//               img.src = img.dataset.src
//             }
//           } else if (lazyElement.tagName === "UNI-VIDEO") {
//             const video = lazyElement as HTMLVideoElement
//             const source = video.querySelector("source")
//             if (source && source.dataset.src) {
//               source.src = source.dataset.src
//               video.load()
//             }
//           }

//           observer.unobserve(lazyElement)
//         }
//       }
//     })

//     observer.observe(el)
//   }
// }
</script>
<style lang="scss" scoped>
.common-waterfall-flow {
  display: flex;
  justify-content: space-between;

  .waterfall-flow-column {
    display: flex;
    flex-direction: column;
  }

  .waterfall-flow-item {
    break-inside: avoid;
    background: #FFF;
    width: 360rpx;
    overflow: hidden;
    border-radius: 8rpx;
    box-shadow: 0 10rpx 20rpx rgba(0, 0, 0, 0.1);
    font-size: 0;

    image,
    video {
      width: 100%;
      height: 0;
    }
  }

  .video-box {
    position: relative;

    .icon-play {
      position: absolute;
      top: 20rpx;
      right: 20rpx;
      background: rgba(0, 0, 0, 0.5);
      width: 40rpx;
      height: 40rpx;
      line-height: 40rpx;
      border-radius: 100%;
      text-align: center;
      font-size: 20rpx;
      color: #FFF;
      z-index: 9;
    }
  }

  .item-content {
    padding: 20rpx;

    .title {
      line-height: 30rpx;
      font-size: 26rpx;
      color: #333;
      @include text-ellipsis(2);
    }

    .game {
      margin: 20rpx 0 0;
      line-height: 24rpx;
      font-size: 24rpx;
      color: #666;
      @include text-ellipsis;
    }

    .more {
      display: flex;
      justify-content: space-between;
      margin: 20rpx 0 0;

      .user {
        flex: 1;
        display: flex;
        align-items: center;

        image {
          width: 40rpx;
          height: 40rpx;
          border-radius: 100%;
        }

        text {
          flex: 1;
          margin-left: 10rpx;
          font-size: 24rpx;
          color: #666;
          @include text-ellipsis;
        }
      }

      .like {
        display: flex;
        align-items: center;
        color: #666;

        &.on {
          color: #F00;
        }

        .iconfont {
          font-size: 26rpx;
        }

        text {
          margin-left: 10rpx;
          font-size: 24rpx;
        }
      }
    }
  }

  .load-list {
    position: absolute;
    top: -1000rpx;
    left: -1000rpx;
    width: 0;
    height: 0;
    overflow: hidden;
  }
}
</style>